//
//  GLAnimation.m
//  LMPhotoVideoSDK
//
//  Created by Aimar on 16/7/19.
//  Copyright © 2016年 魁钺会. All rights reserved.
//

#import "GLAnimation.h"

@interface GLAnimation()

@property (nonatomic, assign)long   currentTime;
@property (nonatomic, assign)float  normalizeTime;
@property (nonatomic, assign)int    repeated;
@property (nonatomic, assign)BOOL   toReverse;
@property (nonatomic, assign)BOOL   more;
@property (nonatomic, assign)BOOL   cycleFlip;
@property (nonatomic, assign)BOOL   oneMoreTime;
@property (nonatomic, assign)BOOL   started;
@property (nonatomic, assign)BOOL   ended;

@end

@implementation GLAnimation

- (void)reset {
    if (!self.toReverse) {
        self.cycleFlip = false;
        self.normalizeTime = 0;
    }
    self.repeated = 0;
    self.more = true;
    self.oneMoreTime = true;
    self.initialized = false;
}

- (void)setStartMillisTime:(long)startTimeMillis {
    if (!self.toReverse) {
        self.startTime = startTimeMillis;
        self.cycleFlip = NO;
    }
    self.started = self.ended = NO;
    self.repeated = 0;
    self.more = YES;
}

- (void)start {
    [self setStartTime:-1];
}

- (void)startNow {
    [self setStartTime:CFAbsoluteTimeGetCurrent() * 1000];
}

- (void)cancel {
    if (self.started && !self.ended) {
        if ([self.delegate respondsToSelector:@selector(onAnimationEnd:)]) {
            [self.delegate onAnimationEnd:self];
        }
        self.ended = YES;
    }
    // Make sure we move the animation to the end
    self.startTime = 0x8000000000000000L;
    self.more = self.oneMoreTime = NO;
}

- (void)initializeWithSize:(CGSize)size parentSize:(CGSize)parentSize {
    [self reset];
    
    self.initialized = true;
    self.toReverse = false;
}

- (BOOL)getTransformation:(long)currentTime outTransform:(mat4*)transform {
    self.currentTime = currentTime;
    
    if (self.startTime == -1) {
        self.startTime = currentTime;
    }
    
    const long startOffset = self.startOffset;
    const long duration = self.duration;
    float normalizedTime;
    if (duration != 0) {
        normalizedTime = ((float) (currentTime - (self.startTime + startOffset))) /
        (float) duration;
    } else {
        // time is a step-change with a zero duration
        normalizedTime = currentTime < self.startTime ? 0.0f : 1.0f;
    }
    
    const BOOL expired = normalizedTime >= 1.0f;
    self.more = !expired;
    
    if (!self.fillEnabled) {
        normalizedTime = MAX(MIN(normalizedTime, 1.0), 0.0);
    }
    
    if ((normalizedTime >= 0.0f || self.fillBefore) && (normalizedTime <= 1.0f || self.fillAfter)) {
        if (!self.started) {
            if ([self.delegate performSelector:@selector(onAnimationStart:)]) {
                [self.delegate onAnimationStart:self];
            }
            self.started = YES;
        }
        
        if (self.fillEnabled) {
            normalizedTime = MAX(MIN(normalizedTime, 1.0f), 0.0f);
        }
        
        if (self.cycleFlip) {
            normalizedTime = 1.0f - normalizedTime;
        }
        
        if (self.interpolator == nil) {
            self.interpolator = [[GLLinearInterpolator alloc] init];
        }
        
        self.normalizeTime = normalizedTime;
        const float interpolatedTime = [self.interpolator getInterpolation:normalizedTime];
        [self applyTransformation:interpolatedTime outTransform:transform];
    }
    
    if (expired) {
        if (self.repeatCount == self.repeated) {
            if (!self.ended) {
                self.ended = YES;
                if ([self.delegate performSelector:@selector(onAnimationEnd:)]) {
                    [self.delegate onAnimationEnd:self];
                }
            }
        } else {
            if (self.repeatCount > 0) {
                self.repeatCount++;
            }
            
            if (self.repeatMode == GLAnimationRepeatMode_Reverse) {
                self.cycleFlip = !self.cycleFlip;
            }
            
            self.startTime = -1;
            self.more = YES;
            
            if ([self.delegate performSelector:@selector(onAnimationRepeat:)]) {
                [self.delegate onAnimationRepeat:self];
            }
        }
    }
    
    if (!self.more && self.oneMoreTime) {
        self.oneMoreTime = NO;
        return YES;
    }
    
    return self.more;
}

- (void)applyTransformation:(float)interpolatedTime outTransform:(mat4*)transform {
    // TODO: subclass need overide this method
}

- (BOOL)willChangeTransformationMatrix {
    return YES;
}

- (BOOL)willChangeBounds {
    return YES;
}

@end
